/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Bank;

/**
 *
 * @author karakots
 */
public class BankBooks {
    private double cash;
    private Bank myBank;
    private double deposits;
    private double loanBalanceOutstanding;
    private double reserveRequired;
    private double loansAmountPreApproved;
    private double numLoansCurrentlyFunded;
    private double numDefaults;
    private double amountLoansEverFunded;

    private double cashQtrDelta;
    private double qtrCash;
    private double depositsQtrDelta;
    private double qtrDeposits;
    private double loanBalanceOustandingQtrDelta;
    private double qtrLoanBalanceOutstanding;

    private double reserveRequiredQtrDelta;
    private double qtrReserveRequired;
    private double loanAmountPreapprovedQtrDelta;
    private double qtrLoanAmountPreaproved;
    private double amountAvailableToLoanQtrDelta;
    private double qtrAmountAvailableToLoan;
    private double equityQtrDelta;
    private double qtrEquity;

    private double numLoansFundedLastQtr;
    private double numDefaultsLastQtr;
    private double numLoansFundedThisQtr;
    private double numDefaultsThisQtr;
    private double amountLoansFundedThisQtr;
    private LendingPolicy lp;

    // accessors
    public void setMyBank(Bank b) {
        myBank = b;
        lp = myBank.getLendingPolicy();
    }
    public double getCashBalance()                      {return cash; }
    public double getNumLoansFunded()                   {return numLoansCurrentlyFunded; }
    public double getAvailableCash()                    {return cash - reserveRequired; }
    public double getNumDefaults()                      {return numDefaults;}
    public double getLoanBalanceOutstanding()           {return loanBalanceOutstanding;}
    public double getLoanAmountPreapproved()            {return loansAmountPreApproved;}
    public double getDeposits()                         {return deposits;}
    public double getReserveRequired()                  {return reserveRequired;}

    public double getLastQtrCash()                      {return cashQtrDelta;}
    public double getLastQtrDeposits()                  {return depositsQtrDelta;}
    public double getLastQtrLoanBalanceOutstanding()    {return loanBalanceOustandingQtrDelta;}
    public double getLastQtrReserveRequired()           {return reserveRequiredQtrDelta; }
    public double getLastQtrLoansAmountPreApproved()    {return loanAmountPreapprovedQtrDelta;}
    public double getNumLoansFundedThisQtr()            {return numLoansFundedThisQtr;}
    public double getNumDefaultsThisQtr()               {return numDefaultsLastQtr;}
    public double getLastQtrAmountAvialableToLoan()     {return amountAvailableToLoanQtrDelta;}
    public double getLastQtrEquity()                    {return equityQtrDelta;}
    public double getAmountLoansEverFunded()            {return amountLoansEverFunded;}
    public double getAmountLoansFundedThisQtr()         {return amountLoansFundedThisQtr;}

    public enum Transaction {
        DEPOSIT, WITHDRAWL, SAVINGSINTEREST, FUNDMORTGAGE, MORTGAGEINTEREST, MORTGAGEPRINCIPAL,
        POINTSPAYMENT, EQUITY, LOANPREAPPROVAL, LOANPREAPPROVALEXPIRED, MORTGAGEPAIDOFF, MORTGAGEDEFAULT,
        MORTGAGESOLD, MORTGAGEBOUGHT, CLOSE
    } 

    public void transaction(double amount, Transaction va) {
        switch (va) {
            case DEPOSIT:
                cash += amount;
                deposits += amount;
                ComputeReserveRequirement();
                break;
            case WITHDRAWL:
                cash -= amount;
                deposits -= amount;
                ComputeReserveRequirement();
                break;
            case SAVINGSINTEREST:
                deposits += amount;
                ComputeReserveRequirement();
                break;
            case FUNDMORTGAGE:
                cash -= amount;
                loansAmountPreApproved -= amount;
                loanBalanceOutstanding += amount;
                amountLoansEverFunded += amount;
                amountLoansFundedThisQtr += amount;
                numLoansCurrentlyFunded++;
                numLoansFundedThisQtr++;
                lp.loanFunded();
                break;
            case MORTGAGEINTEREST:
                cash += amount;
                break;
            case MORTGAGEPRINCIPAL:
                cash += amount;
                loanBalanceOutstanding -= amount;
                if (loanBalanceOutstanding < 0) {
                    boolean wawaoo = true;
                }
                break;
            case POINTSPAYMENT:
                cash += amount;
                break;
            case EQUITY:
                cash += amount;
                break;
            case LOANPREAPPROVAL:
                loansAmountPreApproved += amount;
                lp.preApproveLoan();
                break;
            case LOANPREAPPROVALEXPIRED:
                loansAmountPreApproved -= amount;
                lp.preapprovedExpired();
                break;
            case MORTGAGEPAIDOFF:
                numLoansCurrentlyFunded--;
                lp.mortgagePaidOff();
                break;
            case MORTGAGEDEFAULT:
                numDefaults++;
                numDefaultsThisQtr++;
                lp.loanDefault();
                break;
            case MORTGAGESOLD:
                numLoansCurrentlyFunded--;
                loanBalanceOutstanding -= amount;
                if (loanBalanceOutstanding < 0) {
                    boolean wawaoo = true;
                }
                break;
            case MORTGAGEBOUGHT:
                numLoansCurrentlyFunded++;
                loanBalanceOutstanding+= amount;
                break;
            case CLOSE:
                numLoansCurrentlyFunded = 0;
                loansAmountPreApproved = 0;
                reserveRequired = 0;
                cash = 0;
                loansAmountPreApproved = 0;
                deposits = 0;
                break;
        }
    }

    public boolean canFundMortgage(double requestedAmount) {
        return (getAvailableCash() >= requestedAmount);
    }

    public void newQuarter() {

        cashQtrDelta = cash - qtrCash;
        qtrCash = cash;

        depositsQtrDelta = deposits - qtrDeposits;
        qtrDeposits = deposits;

        loanBalanceOustandingQtrDelta = loanBalanceOutstanding - qtrLoanBalanceOutstanding;
        qtrLoanBalanceOutstanding = loanBalanceOutstanding;

        reserveRequiredQtrDelta = reserveRequired - qtrReserveRequired;
        qtrReserveRequired = reserveRequired;

        loanAmountPreapprovedQtrDelta = loansAmountPreApproved - qtrLoanAmountPreaproved;
        qtrLoanAmountPreaproved = loansAmountPreApproved;

        amountAvailableToLoanQtrDelta = getAmountAvialableToLoanExcludingOffers() - qtrAmountAvailableToLoan;
        qtrAmountAvailableToLoan = getAmountAvialableToLoanExcludingOffers();

        equityQtrDelta = getEquity() - qtrEquity;
        qtrEquity = getEquity();

        numLoansFundedLastQtr = numLoansFundedThisQtr;
        numDefaultsLastQtr = numDefaultsThisQtr;
        numLoansFundedThisQtr = 0;
        numDefaultsThisQtr = 0;
        amountLoansFundedThisQtr = 0;
    }

    public void ComputeReserveRequirement() {
        reserveRequired = deposits * myBank.getReservaRate();
    }

    public boolean getFailed() {
        return (reserveRequired > cash);
    }

    public double getEquity() {
        // technically the assets should include the present value of loans not yet paid
        // this would include interest
        // pv = C/i * (1-1/pow((1+i),n))
        // source: http://en.wikipedia.org/wiki/Present_value
        // less the expected default rate.  But we'll just count the principal now
        return cash - deposits + loanBalanceOutstanding;
    }
    // used to understand if we can offer more mortgages

    public double getAmountAvialableToLoanExcludingOffers() {
        // the conservative assumption is that all pre-approved loans will be accepted
        //return (cash - loansAmountPreApproved - reserveRequired);
        // the really conservative assumption is that all offers will be accepted
        return (cash - reserveRequired - (lp.getNumLoansCurrentlyOnOffer() * lp.maxLoanSize));
    }

    public double getAmountAvailableToLoan() {
        return (cash - reserveRequired);
    }

    public void reset() {
        cash = 0;
        deposits = 0;
        loanBalanceOutstanding = 0;
        reserveRequired = 0.0;
        loansAmountPreApproved = 0;
        numLoansCurrentlyFunded = 0;
        numDefaults = 0;

        cashQtrDelta = 0;
        qtrCash = 0;
        depositsQtrDelta = 0;
        qtrDeposits= 0;
        loanBalanceOustandingQtrDelta = 0;
        qtrLoanBalanceOutstanding = 0;
        reserveRequiredQtrDelta = 0;
        qtrReserveRequired = 0;
        loanAmountPreapprovedQtrDelta = 0;
        qtrLoanAmountPreaproved = 0;
        amountAvailableToLoanQtrDelta = 0;
        qtrAmountAvailableToLoan = 0;
        equityQtrDelta = 0;
        qtrEquity = 0;
        amountLoansEverFunded = 0;
        
        numLoansFundedLastQtr = 0;
        numDefaultsLastQtr = 0;
        numLoansFundedThisQtr = 0;
        numDefaultsThisQtr = 0;
    }
}
